﻿using DoNet.ApiHttpClient.Certificate;
using System.Collections.Concurrent;
using System.Security;
using System.Security.Cryptography.X509Certificates;

namespace DoNet.ApiHttpClient.WechatMch
{
    /// <summary>
    ///  微信支付证书管理器
    /// </summary>
    public class WechatMchManager
    {
        /// <summary>
        /// 证书列表 (名称，证书)
        /// </summary>
        private readonly ConcurrentDictionary<string, X509Certificate2> _certificates = new();
        private readonly ICertificateLoader _loader;
        private readonly TimeSpan _refreshInterval;
        private readonly string basePath = "Certs/WechatMch/";
        private readonly string fileName = "apiclient_cert";
        private readonly string fileExt = "p12";

        /// <summary>
        /// 
        /// </summary>
        /// <param name="loader"></param>
        /// <param name="refreshInterval"></param>
        public WechatMchManager(ICertificateLoader loader, TimeSpan refreshInterval)
        {
            _loader = loader;
            _refreshInterval = refreshInterval;
            StartAutoRefresh();
        }
        /// <summary>
        /// 
        /// </summary>
        private void StartAutoRefresh()
        {
            Task.Run(async () => {
                while (true)
                {
                    await Task.Delay(_refreshInterval);
                    RefreshAllCertificates();
                }
            });
        }
        /// <summary>
        /// 
        /// </summary>
        private void RefreshAllCertificates()
        {
            foreach (var item in _certificates)
            {
                var name = item.Key;
                var oldCert = item.Value;
                if (oldCert != null && oldCert.NotAfter < DateTime.UtcNow.AddDays(7))
                {
                    var newCert = _loader.LoadCertificate(basePath, name, fileName, fileExt);
                    if (newCert != null && newCert.NotAfter > DateTime.UtcNow)
                    {
                        _certificates[name] = newCert;
                    }
                    else
                    {
                        RemoveCertificate(name);
                    }
                }
            }
        }
        /// <summary>
        /// 获取证书
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public X509Certificate2 GetCertificate(string name)
        {
            return _certificates.GetOrAdd(name, id => {
                var cert = _loader.LoadCertificate(basePath, id, fileName, fileExt);

                //此处没看出有什么意义  难道是即将过期提示
                ValidateCertExpiration(cert);

                return cert;
            });
        }

        /// <summary>
        /// 移除证书
        /// </summary>
        /// <param name="name"></param>
        public void RemoveCertificate(string name) => _certificates.TryRemove(name, out _);
        /// <summary>
        /// 获取所有证书列表
        /// </summary>
        /// <returns></returns>
        public IEnumerable<X509Certificate2> GetAllCertificates() => _certificates.Values.ToList();
        /// <summary>
        /// 
        /// </summary>
        /// <param name="cert"></param>
        /// <exception cref="SecurityException"></exception>
        private void ValidateCertExpiration(X509Certificate2 cert)
        {
            if (cert.NotAfter < DateTime.UtcNow.AddDays(7))
            {
                throw new SecurityException($"证书{cert.Thumbprint}将在7天内过期");
            }
        }
    }
}
